#pragma once

#include <metalc/cls/_cls.h>
 
/* snmalloc 使用的szcls */
/* init可以初始化数组进行转换, 可能速度快一点? */
// DECL_SZLCS(prime)

#define MANTISSA_BITS_DEFAULT	(2)
#define MANTISSA_MASK_DEFAULT	MASK_LOW(MANTISSA_BITS_DEFAULT)
#define LOW_BITS_DEFAULT	(4)	/* 最低是16 */

/* 只能用于低级 */
/* 这是个可以求出来的常数 */
#define CLS_NR_super(bits_min, bits_max)	SUPERCLS_CLSC(POW2_M(bits_max))
#define CLS_ASSERT_super(bits_min, bits_max)	(bits_max >= (MANTISSA_BITS + LOW_BITS))

/* WORD_WIDTH - clz_generic() 可以换成fls? 能省去一次减法吗?似乎不行  */

#define SUPERCLS_E(sz, MANTISSA_BITS, LOW_BITS) \
(WORD_WIDTH - MANTISSA_BITS - LOW_BITS - clz_generic((sz - 1UL) | BIT(MANTISSA_BITS + LOW_BITS - 1)))

// #define SUPERCLS_E(sz, MANTISSA_BITS, LOW_BITS) \
// (fls_generic(((sz) - 1UL) | BIT(MANTISSA_BITS + LOW_BITS - 1)) - MANTISSA_BITS - LOW_BITS)

#define SUPERCLS_B(sz, MANTISSA_BITS, LOW_BITS) \
((SUPERCLS_E(sz, MANTISSA_BITS, LOW_BITS) == 0) ? 0 : 1)

#define SUPERCLS_M(sz, MANTISSA_BITS, LOW_BITS) \
(((sz - 1) >> (LOW_BITS + SUPERCLS_E(sz, MANTISSA_BITS, LOW_BITS) - SUPERCLS_B(sz, MANTISSA_BITS, LOW_BITS))) & MASK_LOW(MANTISSA_BITS))

#define SUPERCLS_CLS(sz, MANTISSA_BITS, LOW_BITS) \
((SUPERCLS_E(sz, MANTISSA_BITS, LOW_BITS) << MANTISSA_BITS) + SUPERCLS_M(sz, MANTISSA_BITS, LOW_BITS))

// #define SUPERCLS_EC(sz) (WORD_WIDTH - MANTISSA_BITS - LOW_BITS - LOG2_M(sz))
// #define SUPERCLS_BC(sz) ((SUPERCLS_EC(sz) == 0) ? 0 : 1)
// #define SUPERCLS_MC(sz) ( ((sz - 1) >> (LOW_BITS + SUPERCLS_EC(sz) - SUPERCLS_BC(sz))) & MANTISSA_MASK)
// #define SUPERCLS_CLSC(sz) ((SUPERCLS_EC(sz) << MANTISSA_BITS) + SUPERCLS_MC(sz))

#define SUPERCLS_SZE(sc, MANTISSA_BITS) \
((sc+1) >> MANTISSA_BITS)

#define SUPERCLS_SZB(sc, MANTISSA_BITS) \
((SUPERCLS_SZE(sc, MANTISSA_BITS) == 0) ? 0 : 1)

#define SUPERCLS_SZM(sc, MANTISSA_BITS) \
((sc+1) & MASK_LOW(MANTISSA_BITS))

#define SUPERCLS_SZ(sc, MANTISSA_BITS, LOW_BITS) \
((SUPERCLS_SZM(sc, MANTISSA_BITS) + (SUPERCLS_SZB(sc, MANTISSA_BITS) << MANTISSA_BITS)) << (LOW_BITS + SUPERCLS_SZE(sc, MANTISSA_BITS) - SUPERCLS_SZB(sc, MANTISSA_BITS)))


#define __sz2cls_super(size, MANTISSA_BITS, LOW_BITS)		SUPERCLS_CLS(size, MANTISSA_BITS, LOW_BITS)
#define __cls2sz_super(cls, MANTISSA_BITS, LOW_BITS)		SUPERCLS_SZ(cls, MANTISSA_BITS, LOW_BITS)

#define __clsnr_super(bits_max, MANTISSA_BITS, LOW_BITS)	SUPERCLS_CLS(BIT(bits_max), MANTISSA_BITS, LOW_BITS)



#define DEF_CLS_SUPER(name, MINSZBIT, MAXSZBIT, MANTISSA_BITS, LOW_BITS)			\
DECL_SZLCS(name)										\
SASSERT(MAXSZBIT > (MANTISSA_BITS + LOW_BITS));							\
static const szcls_t _clsnr_##name = (szcls_t)__clsnr_super(MAXSZBIT, MANTISSA_BITS, LOW_BITS);	\
static const size_t _maxsz_##name = __cls2sz_super(_clsnr_##name - 1, MANTISSA_BITS, LOW_BITS);\
SAI PURE szcls_t _sz2cls_##name (size_t size){ ASSERT(size >= 1); return __sz2cls_super(size, MANTISSA_BITS, LOW_BITS); };\
SAI PURE size_t _cls2sz_##name (szcls_t cls){ return __cls2sz_super(cls, MANTISSA_BITS, LOW_BITS); };


/* 先拼接字符串 */
#define CLS2SZ_SUPER(cls)	__cls2sz_super(cls, MANTISSA_BITS_DEFAULT, LOW_BITS_DEFAULT)


#define DEF_SUPER_CLS2SZ_MAPTBL(name, cls_nr, MANTISSA_BITS, LOW_BITS) \
static const size_t __cls2sz_tbl_##name [] = { MAPC(CLS2SZ_SUPER, RANGE8(64)) };\

/* 通过表加速转换过程 */
#define DEF_CLS_SUPER_CLS2SZTBL(name, MINSZBIT, MAXSZBIT, MANTISSA_BITS, LOW_BITS)		\
DECL_SZLCS(name)										\
SASSERT(MAXSZBIT > (MANTISSA_BITS + LOW_BITS));							\
SASSERT((MANTISSA_BITS == MANTISSA_BITS_DEFAULT) && (LOW_BITS_DEFAULT == LOW_BITS));		\
DEF_SUPER_CLS2SZ_MAPTBL(name, __clsnr_super(MAXSZBIT, MANTISSA_BITS, LOW_BITS), MANTISSA_BITS, LOW_BITS)\
static const szcls_t _clsnr_##name = (szcls_t)__clsnr_super(MAXSZBIT, MANTISSA_BITS, LOW_BITS);	\
static const size_t _maxsz_##name = __cls2sz_super(_clsnr_##name - 1, MANTISSA_BITS, LOW_BITS);\
SASSERT( __clsnr_super(MAXSZBIT, MANTISSA_BITS, LOW_BITS) < 64);\
SAI PURE szcls_t _sz2cls_##name (size_t size){ ASSERT(size >= 1); return __sz2cls_super(size, MANTISSA_BITS, LOW_BITS); }\
SAI PURE size_t _cls2sz_##name (szcls_t cls){ return __cls2sz_tbl_##name [cls]; }


// SAI PURE szcls_t __sz2cls_super(const size_t min_size, const size_t max_size, size_t size)
// {
//     // SASSERT(min_size >= (1UL << LOW_BITS));
//     // size--;
//     // szcls_t e = 58 - clz_generic(size | 32);
//     // szcls_t b = (e == 0) ? 0 : 1;
//     // szcls_t m = (size >> (4 + e - b)) & 3;
//     // return (e << 2) + m;
//     return SUPERCLS_CLS(size);
// }

// SAI PURE size_t __cls2sz_super(const size_t min_size, const size_t max_size, szcls_t sc)
// {
//     // sc++;
//     // size_t m = sc & 3;
//     // size_t e = sc >> 2;
//     // size_t b = (e == 0) ? 0 : 1;
//     // return (m + (b * 4)) << (4 + e - b);
//     return SUPERCLS_SZ(sc);
// }
